package rolesystem.examples.jade.auction.bidder;

import rolesystem.core.*;
import rolesystem.roles.auction.*;
import rolesystem.jade.agents.*;

import java.io.Serializable;

/**
 * This class represents a possible behaviour of a bidder.
 * This is a subject layer that can be used by agents in a role system.
 */
public class BidderSL implements SubjectLayer
{
	/**
	 * Time to wait between searches, in milliseconds.
	 */
	private static final long PAUSE=2000;

	/**
	 * Maximum time to wait for replies.
	 */
	private static final long REPTO=3000;

	/**
	 * Description of searched good.
	 */
	private String goodDesc;

	/**
	 * Available money.
	 */
	private Price budget;

	/**
	 * Bought good.
	 */
	private Serializable good;


	/**
	 * @param goodDesc Description of searched good.
	 * @param budget Available money.
	 */
	public BidderSL(String goodDesc, Price budget)
	{
		this.goodDesc=goodDesc;
		this.budget=budget;
	}
	
	
	public void go(RoleSystem roleSystem)
	{
		RoleRegistration registration;
		int[] auctioneersArray;
		int count;
		int auctioneer=0;
		RoleEvent event;
		Price price=null;
		boolean again1;
		boolean again2;
		boolean again3;
		long residualTime, finalTime;

		try
		{
			registration=roleSystem.reqRegistration(Bidder.ROLE_ID);
		}
		catch(RoleException re)
		{
			System.err.println(re);
			return;
		}
		try
		{
			// Loop until an auction with a suitable good is won.
			again1=true;
			do
			{
				try
				{
					System.out.println("Looking for a suitable auction...");
					// Loop until a suitable auction is found.
					again2=true;
					do
					{
						try
						{
							Thread.sleep(PAUSE);
						}
						catch(InterruptedException ie)
						{
						}
						auctioneersArray=roleSystem.searchForRole(Auctioneer.ROLE_ID);
						System.out.println("Found "+auctioneersArray.length+" auctioneers");
						count=(int)(Math.random()*auctioneersArray.length);
						auctioneer=auctioneersArray[count];
						System.out.println("Asking good to auctioneer "+count+", role id "+auctioneer);

						registration.doAction(Bidder.
							askGood(auctioneer));

						// Loop until a suitable reply is received.
						again3=true;
						finalTime=System.currentTimeMillis()+REPTO;
						do
						{
							residualTime=finalTime-System.currentTimeMillis();
							if(residualTime<=0)
								// Timeout elapsed before the auctioneer has replied.
								break;
							event=registration.listen(residualTime);
							if(event==null)
								continue;
							if(event.getSender()==auctioneer)
							{
								// A do...while(false) block is used, so a break
								// causes the exit from this block.
								do
								{
									if(Bidder.KE_notifyGood.match(event))
									{
										System.out.println("The good is "+(String)event.getContent());
										if( goodDesc.equals((String)event.getContent()) )
											again2=false;
										again3=false;
										break;
									}
									if(Bidder.KE_auctionOver.match(event))
									{
										System.out.println("The auction is over");
										again3=false;
										break;
									}
									// Other events are ignored.
								} while(false);
							}
						} while(again3);

						// A suitable reply is received.
					} while(again2);

					System.out.println("Auction found");
					// A suitable auction is found.
					auctioneer=auctioneersArray[count];
					registration.doAction(Bidder.
						askKind(auctioneer));

					// Loop until a suitable reply is received.
					again2=true;
					do
					{
						event=registration.listen();
						if(Bidder.KE_notifyKind.match(event) &&
							event.getSender()==auctioneer)
						{
							if( ((String)event.getContent()).equals("English") )
							{
								price=BidderEng.go(registration,
									auctioneer, budget);
								if( price!=null )
									again1=false;
							}
							again2=false;
						}
					} while(again2);
						}
				catch(RoleException re)
				{
					if(!RoleException.NOT_VALID_ADD.equals(re.getMessage()))
						continue;
					else
						throw re;
				}
			} while(again1);

			// An auction with a suitable good is won.
			// The price to pay is "price".
			budget=new Price(budget.getAmount()-price.getAmount(),
				budget.getCurrency());
			registration.doAction(Bidder.
				pay(auctioneer, new Money(price)));

			// Loop until a suitable reply is received.
			do
			{
				event=registration.listen();
			} while(!(Bidder.KE_giveGood.match(event) &&
				event.getSender()==auctioneer));

			// A suitable reply is received.
			good=event.getContent();
		}
		catch(RoleException re)
		{
			System.err.println(re);
		}
		try
		{
			System.out.println("I'm about to dismiss the registration.");
			registration.dismiss();
		}
		catch(RoleException re)
		{
			System.err.println(re);
		}
	}


	/**
	 * Returns the left money.
	 * @return the left money.
	 */
	public Price getMoney()
	{
		return budget;
	}


	/**
	 * Returns the bought good.
	 * @return the bought good.
	 */
	public Serializable getGood()
	{
		return good;
	}
}
